@ Constants that define various operating modes

.equ  PSR_MASK,         0x0000001F       @ CSPR bits that define operating mode
.equ  MODE_USR,         0x00000010       @ User Mode
.equ  MODE_FIQ,         0x00000011       @ FIQ Mode
.equ  MODE_IRQ,         0x00000012       @ IRQ Mode
.equ  MODE_SVC,         0x00000013       @ Supervisor Mode
.equ  MODE_ABT,         0x00000017       @ Abort Mode
.equ  MODE_UND,         0x0000001B       @ Undefined Mode
.equ  MODE_SYS,         0x0000001F       @ System Mode
.equ FIQ_BIT,           0x00000040       @ FIQ exception enable/disable bit
.equ IRQ_BIT,           0x00000080       @ IRQ exception enable/disable bit
.equ I_BIT,             0x80
.equ F_BIT,             0x40
.equ I_BIT,             0x80
.equ F_BIT,             0x40
.equ EXCEPTION_VECT,    0x00000000   @ Start of exception vectors
.equ  Region_4K,        0x0B
.equ  Region_8K,        0x0C
.equ  Region_16K,       0x0D
.equ  Region_32K,       0x0E
.equ  Region_64K,       0x0F
.equ  Region_128K,      0x10
.equ  Region_256K,      0x11
.equ  Region_512K,      0x12
.equ  Region_1M,        0x13
.equ  Region_2M,        0x14
.equ  Region_4M,        0x15
.equ  Region_8M,        0x16
.equ  Region_16M,       0x17
.equ  Region_32M,       0x18
.equ  Region_64M,       0x19
.equ  Region_128M,      0x1A
.equ  Region_256M,      0x1B
.equ  Region_512M,      0x1C
.equ  Region_1G,        0x1D
.equ  Region_2G,        0x1E
.equ  Region_4G,        0x1F
.equ  Region_Enable,    0x1
.section .init

@ This symbol must be visible to the linker

    .global vectors_start
vectors_start:
    @ Exception vectors, relative to the base address, see page 2-26 of DDI0222
    LDR pc, reset_handler_addr             @ Reset (and startup) vector
    LDR pc, undef_handler_addr             @ Undefined (unknown) instruction
    LDR pc, swi_handler_addr               @ Software interrupt
    LDR pc, prefetch_abort_handler_addr    @ Prefetch abort
    LDR pc, data_abort_handler_addr        @ Data abort (system bus cannot access a peripheral)
    LDR pc, invalid_addr_handler           @ Reserved (early ARM only supported 26-bit addresses)
    LDR pc, irq_handler_addr               @ IRQ handler
    LDR pc, fiq_handler_addr               @ FIQ handler
@ Labels with addresses to exception handler routines, referenced above:

reset_handler_addr:
    .word reset_handler

undef_handler_addr:
    .word vector_undef

swi_handler_addr:
    .word vector_swi

prefetch_abort_handler_addr:
    .word vector_pabt

data_abort_handler_addr:
    .word vector_dabt

invalid_addr_handler:
    .word vector_resv

irq_handler_addr:
    .word vector_irq

fiq_handler_addr:
    .word vector_fiq

.balignl    16,0xdeadbeef
vectors_end:

/*
 * Macro for switching ARM mode
 */
    .macro  BOOT_CHANGE_MODE, mode, mode_mask
    MRS   R0, CPSR
    BIC   R0, R0, #\mode_mask
    ORR   R0, R0, #\mode
    MSR   CPSR_c, R0
    .endm

/*
 * Macro for setting the stack
 */
    .macro  BOOT_SET_STACK, stackStart, stackLen, color
    LDR   R1, \stackStart
    LDR   R0, \stackLen

    SUB   R0, R1, R0
    MOV   SP, R1        //Set stack pointer

    LDR   R2, =\color

3:
    CMP   R0, R1        //End of stack?
    STRLT R2, [r0]      //Colorize stack word
    ADDLT R0, R0, #4
    BLT   3b           //branch to previous local label
    .endm

.text
reset_handler:
    LDR r1, =0x40300000
    LDR r2, =0x00010000 
    STR r2, [r1, #8] 
    LDR r2, =0x00010000
    LDR r1, =0x40300000
    STR r2, [r1]  

    @ The handler is always entered in Supervisor mode
    LDR sp, =svc_stack_top                 @ stack for the supervisor mode

    @  In the reset handler, we need to copy our interrupt vector table to 0x0000, its currently at 0x10000
    LDR r0, =vectors_start                 @ Store the source pointer
    LDR r1, =0x7ff40000                 @ Store the destination pointer.

    @  Copy the branching instructions from vectors start to registers r2-r9 and then to destination
    LDMIA r0!, {r2, r3, r4, r5, r6, r7, r8, r9}     @ Load multiple values from indexed address; auto-increment R0
    STMIA r1!, {r2, r3, r4, r5, r6, r7, r8, r9}     @ Store multiple values from the indexed address; auto-increment R1

    @  Also copy correct addresses of exception handlers
    LDMIA r0!, {r2, r3, r4, r5, r6, r7, r8, r9}
    STMIA r1!, {r2, r3, r4, r5, r6, r7, r8, r9}

    @ Clear the whole BSS section to 0:
    LDR r0, __bss_begin_addr
    LDR r1, __bss_end_addr
    MOV r2, #0

bss_clear_loop:
    CMP r0, r1                     @ if (r0<r1) ....
    STRLTB r2, [r0], #1            @ ...store a byte of r2 (i.r. 0) to location pointed by r0++
    BLT bss_clear_loop             @ ...and continue the loop

    @ Set stack pointers and IRQ/FIQ bits for all supported operating modes
    MRS r0, cpsr                           @ copy Program Status Register (CPSR) to r0
    
    @ Disable IRQ and FIQ interrupts for the Supervisor mode
    @ This should be disabled by default -
    ORR r1, r0, #IRQ_BIT|FIQ_BIT
    MSR cpsr, r1

    @ Switch to System mode and disable IRQ/FIQ
    BIC r1, r0, #PSR_MASK                  @ clear lowest 5 bits
    ORR r1, r1, #MODE_SYS                  @ and set them to the System mode
    ORR r1, r1, #IRQ_BIT|FIQ_BIT           @ disable IRQ and FIW triggering
    MSR cpsr, r1                           @ update CPSR and enter System mode
    LDR sp, =stack_top                     @ set stack for System mode

    @ Set and switch into IRQ mode
    BIC r1, r0, #PSR_MASK                  @ clear least significant 5 bits...
    ORR r1, r1, #MODE_IRQ                  @ and set them to b10010 (0x12), i.e set IRQ mode
    ORR r1, r1, #IRQ_BIT|FIQ_BIT           @ also disable IRQ and FIQ triggering (a default setting, but...)
    MSR cpsr, r1                           @ update CPSR (program status register) for IRQ mode

    @ When in IRQ mode, set its stack pointer
    LDR sp, =irq_stack_top                 @ stack for the IRQ mode
    @ Prepare and enter into System mode.
    BIC r1, r0, #PSR_MASK                  @ clear lowest 5 bits
    ORR r1, r1, #MODE_SYS                  @ and set them to the System mode

    @ Return to Supervisor mode. When the first task starts it will switch
    @ to System mode and enable IRQ triggering.
    BIC r1, r1, #PSR_MASK
    ORR r1, r1, #MODE_SVC
    MSR cpsr, r1

    /* Disable MPU */
    MRC     p15, 0, r0, c1, c0, 0       //read CP15 register 1
    BIC     r0, r0, #0x1                //clear MMU/MPU enable
    MCR     p15, 0, r0, c1, c0, 0       //write value back

    /* Set up region 0 - Background and enable */
    MOV     r0,#(Region_4G << 1)
    ORR     r0, r0, #Region_Enable    
    MCR     p15, 0, r0, c6, c0, 0

    /* Set up region 1 - Background and enable */
    LDR     r0, =(0x7ff4 << 12)              //SRAM BASE
    ORR     r0, r0, #(Region_512K << 1)      //SRAM SIZE
    ORR     r0, r0, #Region_Enable    
    MCR     p15, 0, r0, c6, c1, 0    

    /* Set up region 1 - cacheable /bufferable attributes */ 
    MOV     r0, #2                            //cache bits set for SRAM
    MCR     p15, 0, r0, c2, c0, 0             //data cacheable
    MOV     r0, #2                            //cache bits set for SRAM
    MCR     p15, 0, r0, c2, c0, 1             //instr cacheable
    MOV     r0, #2                            //bufferable bit set for RAM
    MCR     p15, 0, r0, c3, c0, 0             //sets Write Back Cacheing

    /* Set up access permissions */
    MOV     r0, #2 
    ORR     r0, r0,#3                    //Background  set to P: RW,    U: RW
    ORR     r0, r0,#(3 << 4)             //SRAM        set to P: RW,    U: RW

    /* In this example the access permissions are the same for both instruction and data sides
        Apply these to both instruction and data side */
    MCR     p15, 0, r0, c5, c0, 2       //data AP
    MCR     p15, 0, r0, c5, c0, 3       //instr AP

    /* Disable I/D Caches */
    MRC     p15, 0, r0, c1, c0, 0   // Read Control Register configuration data
    BIC     r0, r0, #(0x1 << 12)    // Disable I Cache
    BIC     r0, r0, #(0x1 << 2)     // Disable D Cache
    MCR     p15, 0, r0, c1, c0, 0   // Write Control Register configuration data

    /* D-Cache Enable */
    MRC p15, 0, r0, c1, c0, 0
    ORR r0, r0, #(0x1<<2)            //Enable D Cache
    ORR    r0, r0, #0x1              // must enable MPU
    MCR p15, 0, r0, c1, c0, 0

    /* I-Cache Enable */
    MRC     p15, 0, r0, c1, c0, 0    // Read Control Register configuration data
    ORR     r0, r0, #(0x1 << 12)     // Enable I Cache
    ORR    r0, r0, #0x1              // must enable MPU
    MCR p15, 0, r0, c1, c0, 0        // Write Control Register configuration data
 
	/* start RT-Thread Kernel */
    ldr     pc, _rtthread_startup
_rtthread_startup:
    .word  rtthread_startup

/*
 ***************************************
 * exception handlers 
 ***************************************
 */
    /* Interrupt */
vector_fiq:
    stmfd   sp!,{r0-r7,lr}
    bl      rt_hw_trap_fiq
    ldmfd   sp!,{r0-r7,lr}
    subs    pc, lr, #4

vector_irq:
    stmfd   sp!, {r0-r12,lr}

    bl      rt_interrupt_enter
    bl      rt_hw_trap_irq
    bl      rt_interrupt_leave

    ldr     r0, =rt_thread_switch_interrupt_flag
    ldr     r1, [r0]
    cmp     r1, #1
    beq     rt_hw_context_switch_interrupt_do

    ldmfd   sp!, {r0-r12,lr}
    subs    pc,  lr, #4

rt_hw_context_switch_interrupt_do:
    mov     r1,  #0         
    str     r1,  [r0]

    mov     r1, sp          
    add     sp, sp, #4*4
    ldmfd   sp!, {r4-r12,lr}
    mrs     r0,  spsr       
    sub     r2,  lr, #4     

    msr     cpsr_c, #I_BIT|F_BIT|MODE_SVC

    stmfd   sp!, {r2}       
    stmfd   sp!, {r4-r12,lr}
    ldmfd   r1,  {r1-r4}    
    stmfd   sp!, {r1-r4}    
    stmfd   sp!, {r0}       

    ldr     r4,  =rt_interrupt_from_thread
    ldr     r5,  [r4]
    str     sp,  [r5]       

    ldr     r6,  =rt_interrupt_to_thread
    ldr     r6,  [r6]
    ldr     sp,  [r6]       

    ldmfd   sp!, {r4}       
    msr     spsr_cxsf, r4

    ldmfd   sp!, {r0-r12,lr,pc}^ 

    /* Exception */
.macro push_svc_reg
    sub     sp, sp, #17 * 4
    stmia   sp, {r0 - r12} 
    mov     r0, sp
    mrs     r6, spsr       
    str     lr, [r0, #15*4]
    str     r6, [r0, #16*4]
    str     sp, [r0, #13*4]
    str     lr, [r0, #14*4]
.endm

vector_swi:
    push_svc_reg
    bl      rt_hw_trap_swi
    b       .

vector_undef:
    push_svc_reg
    bl      rt_hw_trap_udef
    b       .

vector_pabt:
    push_svc_reg
    bl      rt_hw_trap_pabt
    b       .

vector_dabt:
    push_svc_reg
    bl      rt_hw_trap_dabt
    b       .

vector_resv:
    push_svc_reg
    bl      rt_hw_trap_resv
    b       .

@ Addresses of BSS begin and end.

@ Note that both symbols have been defined in the linker script

__bss_begin_addr:

    .word __bss_start

__bss_end_addr:

    .word __bss_end

.end